﻿using System.Text.RegularExpressions;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace XRpgLibrary.ExtensionMethods
{
    /// <summary>
    /// This class extends the SpriteBatch class.
    /// </summary>
    public static class SpriteBatchExtension
    {
        /// <summary>
        /// Adds a sprite string to the batch of sprites to be rendered with a color-gradient overlay, specifying the font, output text, screen position, and the start- and end-colors of the gradient.
        /// </summary>
        /// <param name="spriteBatch">The spriteBatch which will do the drawing.</param>
        /// <param name="spriteFont">The sprite font.</param>
        /// <param name="text">The string to draw.</param>
        /// <param name="position">The location, in coordinates, where the text will be drawn.</param>
        /// <param name="gradientStart">The beginning color of the desired gradient.</param>
        /// <param name="gradientEnd">The end color of the desired gradient.</param>
        public static void DrawString(this SpriteBatch spriteBatch, 
            SpriteFont spriteFont, 
            string text,
            Vector2 position, 
            Color gradientStart, 
            Color gradientEnd)
        {
            //Store the current position in the text
            Vector2 offset = Vector2.Zero;

            //Calculate a color for each character in the text
            Color[] colorSteps = CreateColorSteps(gradientStart, gradientEnd, text.Length);


            //Loop through every character in the text, drawing it with
            //the next color in the gradient sequence, and adding its
            //length to the offset.
            for (int x = 0; x < text.Length; x++)
            {
                spriteBatch.DrawString(spriteFont, text[x].ToString(), position + offset, colorSteps[x]);
                offset.X += spriteFont.MeasureString(text[x].ToString()).X;
            }

        }

        /// <summary>
        /// Adds a sprite string to the batch of sprites to be rendered with a special color for a specified pattern
        /// </summary>
        /// <param name="spriteBatch">The spriteBatch which will do the drawing.</param>
        /// <param name="spriteFont">The sprite font.</param>
        /// <param name="text">The string to draw.</param>
        /// <param name="pattern">Regex pattern to select different colored text with</param>
        /// <param name="position">The location, in coordinates, where the text will be drawn.</param>
        /// <param name="normalColor">The normal color of the string.</param>
        /// <param name="specialColor">The color for the special substrings.</param>
        public static void DrawString(this SpriteBatch spriteBatch,
            SpriteFont spriteFont,
            string text,
            string pattern,
            Vector2 position,
            Color normalColor,
            Color specialColor)
        {
            Vector2 offset = Vector2.Zero;
            Color currentColor = normalColor;

            string[] substrings = Regex.Split(text, @"(\**?\*)", RegexOptions.IgnoreCase);
                
            for (int x = 0; x < substrings.Length; x++)
            {
                if (substrings[x] == "*")
                {
                    currentColor = currentColor == normalColor ? specialColor : normalColor;
                    continue;
                }
                    

                spriteBatch.DrawString(spriteFont, substrings[x], position + offset, currentColor);
                offset.X += spriteFont.MeasureString(substrings[x]).X;
            }
        }

        /// <summary>
        /// Creates an array of Colors, forming a gradient with the specified number of steps.
        /// </summary>
        /// <param name="start">The desired starting color of the gradient.</param>
        /// <param name="end">The desired ending color of the gradient.</param>
        /// <param name="numSteps">The length of the gradient array.</param>
        /// <returns>The resulting array of colors in the gradient.</returns>
        private static Color[] CreateColorSteps(Color start, Color end, int numSteps)
        {
            //Stores the resulting array of colors in the gradient
            Color[] result = new Color[numSteps];

            //Loop through every step in the gradient,
            //calculating the appropriate color at that point
            for (int x = 0; x < numSteps; x++)
            {
                byte r, g, b, a;

                r = (byte)MathHelper.Lerp((float)start.R, (float)end.R, (float)x / (float)numSteps);
                g = (byte)MathHelper.Lerp((float)start.G, (float)end.G, (float)x / (float)numSteps);
                b = (byte)MathHelper.Lerp((float)start.B, (float)end.B, (float)x / (float)numSteps);
                a = (byte)MathHelper.Lerp((float)start.A, (float)end.A, (float)x / (float)numSteps);

                result[x] = new Color(r, g, b, a);
            }

            return result;
        }
    }
}
